﻿/*******************************************************************************
 * Copyright (c) 2000, 2003 IBM Corporation and others.
 * All rights reserved. This program and the accompanying materials 
 * are made available under the terms of the Common Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/cpl-v10.html
 * 
 * Contributors:
 *     IBM Corporation - initial API and implementation
 *******************************************************************************/
module dwt.widgets.imagelist;


private import dwt.dwt;


private import dwt.internal.win32.os;

private import dwt.graphics.color;
private import dwt.graphics.font;
private import dwt.graphics.image;
private import dwt.graphics.point;
private import dwt.graphics.rectangle;
private import dwt.util.util;




class ImageList {
	
	HIMAGELIST handle;
	int refCount;
	Image [] images;
	static int CREATE_FLAGS;
	private static boolean staticCtor_done = false;
	static void staticCtor() {
		if(staticCtor_done) return;
		staticCtor_done = true;
	
		version(WinCE) {
			CREATE_FLAGS = OS.ILC_MASK | OS.ILC_COLOR;
		} else {
			int flags = OS.ILC_MASK;
			HDC hDC = OS.GetDC (null);
			int bits = OS.GetDeviceCaps (hDC, OS.BITSPIXEL);
			int planes = OS.GetDeviceCaps (hDC, OS.PLANES);
			OS.ReleaseDC (null, hDC);
			int depth = bits * planes;
			switch (depth) {
				case 4:
					flags |= OS.ILC_COLOR4;
					break;
				case 8:
					flags |= OS.ILC_COLOR8;
					break;
				case 16:
					flags |= OS.ILC_COLOR16;
					break;
				case 24:
					flags |= OS.ILC_COLOR24;
					break;
				case 32:
					flags |= OS.ILC_COLOR32;
					break;
				default:
					flags |= OS.ILC_COLOR;
			}
			CREATE_FLAGS = flags;
		}
	}
	
public this () {
	staticCtor();
	
	handle = OS.ImageList_Create (32, 32, CREATE_FLAGS, 16, 16);
	images = new Image [4];
}

public int add (Image image) {
	int count = OS.ImageList_GetImageCount (handle);
	int index = 0;
	while (index < count) {
		if (images [index] !is null) {
			if (images [index].isDisposed ()) images [index] = null;
		}
		if (images [index] is null) break;
		index++;
	}
	int [] cx = new int [1], cy = new int [1];
	if (count == 0) {
		Rectangle rect = image.getBounds();
		cx [0] = rect.width;
		cy [0] = rect.height;
		OS.ImageList_SetIconSize (handle, cx [0], cy [0]);
	}
	HBITMAP hImage = image.handle;
	OS.ImageList_GetIconSize (handle, cx.ptr, cy.ptr);
	switch (image.type) {
		case DWT.BITMAP: {
			HBITMAP hBitmap = copyBitmap (hImage, cx [0], cy [0]);
			int background = -1;
			Color color = image.getBackground ();
			if (color !is null) background = color.handle;
			if (index == count) {
				if (background != -1) {
					OS.ImageList_AddMasked (handle, hBitmap, background);
				} else {
					HBITMAP hMask = createMask (hBitmap, cx [0], cy [0], background);
					OS.ImageList_Add (handle, hBitmap, hMask);
					OS.DeleteObject (hMask);
				}
			} else {
				HBITMAP hMask = createMask (hBitmap, cx [0], cy [0], background);
				OS.ImageList_Replace (handle, index, hBitmap, hMask);
				OS.DeleteObject (hMask);
			}
			OS.DeleteObject (hBitmap);
			break;
		}
		case DWT.ICON: {
			version(WinCE) {	
				OS.ImageList_ReplaceIcon (handle, index == count ? -1 : index, hImage);
			} else {
				HICON hIcon= copyIcon (hImage, cx [0], cy [0]);
				OS.ImageList_ReplaceIcon (handle, index == count ? -1 : index, hIcon);
				OS.DestroyIcon (hIcon);
			}
			break;
		}
		default : break;
	}
	if (index == images.length) {
		Image [] newImages = new Image [images.length + 4];
		System.arraycopy (cast(Object[])images, 0, cast(Object[])newImages, 0, images.length);
		images = newImages;
	}
	images [index] = image;
	return index;
}

int addRef() {
	return ++refCount;
}

HBITMAP copyBitmap (HBITMAP hImage, int width, int height) {
	BITMAP* bm = new BITMAP ();
	OS.GetObject (hImage, BITMAP.sizeof, bm);
	HDC hDC = OS.GetDC (null);
	HDC hdc1 = OS.CreateCompatibleDC (hDC);
	OS.SelectObject (hdc1, hImage);
	HDC hdc2 = OS.CreateCompatibleDC (hDC);
	HBITMAP hBitmap = OS.CreateCompatibleBitmap (hDC, width, height);
	OS.SelectObject (hdc2, hBitmap);
	if (width != bm.bmWidth || height != bm.bmHeight) {
		version(WinCE) {} else {  OS.SetStretchBltMode(hdc2, OS.COLORONCOLOR); }
		OS.StretchBlt (hdc2, 0, 0, width, height, hdc1, 0, 0, bm.bmWidth, bm.bmHeight, OS.SRCCOPY);
	} else {
		OS.BitBlt (hdc2, 0, 0, width, height, hdc1, 0, 0, OS.SRCCOPY);
	}
	OS.DeleteDC (hdc1);
	OS.DeleteDC (hdc2);
	OS.ReleaseDC (null, hDC);
	return hBitmap;
}

HICON copyIcon (HBITMAP hImage, int width, int height) {
	version(WinCE) { DWT.error(__FILE__, __LINE__, DWT.ERROR_NOT_IMPLEMENTED); }
	HICON hIcon= OS.CopyImage (hImage, OS.IMAGE_ICON, width, height, OS.LR_DEFAULTCOLOR);
	return hIcon !is null ? hIcon : hImage;
}

HBITMAP createMask (HBITMAP hBitmap, int width, int height, int background) {
	HBITMAP hMask = OS.CreateBitmap (width, height, 1, 1, null);
	HDC hDC = OS.GetDC (null);
	HDC hdc1 = OS.CreateCompatibleDC (hDC);
	if (background != -1) {
		OS.SelectObject (hdc1, hBitmap);
		HDC hdc2 = OS.CreateCompatibleDC (hDC);
		OS.SelectObject (hdc2, hMask);
		OS.SetBkColor (hdc1, background);
		OS.BitBlt (hdc2, 0, 0, width, height, hdc1, 0, 0, OS.SRCCOPY);
		OS.DeleteDC (hdc2);
	} else {
		HBITMAP hOldBitmap = OS.SelectObject (hdc1, hMask);
		OS.PatBlt (hdc1, 0, 0, width, height, OS.BLACKNESS);
		OS.SelectObject (hdc1, hOldBitmap);
	}
	OS.ReleaseDC (null, hDC);
	OS.DeleteDC (hdc1);
	return hMask;
}

public void dispose () {
	if (handle !is null) OS.ImageList_Destroy (handle);
	handle = null;
	images = null;
}

public Image get (int index) {
	return images [index];
}

public HIMAGELIST getHandle () {
	return handle;
}

public Point getImageSize() {
	int [] cx = new int [1], cy = new int [1];
	OS.ImageList_GetIconSize (handle, cx.ptr, cy.ptr);
	return new Point (cx [0], cy [0]);
}

public int indexOf (Image image) {
	int count = OS.ImageList_GetImageCount (handle);
	for (int i=0; i<count; i++) {
		if (images [i] !is null) {
			if (images [i].isDisposed ()) images [i] = null;
			if (images [i] !is null && images [i].equals (image)) return i;
		}
	}
	return -1;
}

public void put (int index, Image image) {
	int count = OS.ImageList_GetImageCount (handle);
	if (!(0 <= index && index < count)) return;
	if (image !is null) {
		int [] cx = new int [1], cy = new int [1];
		OS.ImageList_GetIconSize (handle, cx.ptr, cy.ptr);
		HBITMAP hImage = image.handle;
		switch (image.type) {
			case DWT.BITMAP: {
				int background = -1;
				Color color = image.getBackground ();
				if (color !is null) background = color.handle;
				HBITMAP hBitmap = copyBitmap (hImage, cx [0], cy [0]);
				HBITMAP hMask = createMask (hBitmap, cx [0], cy [0], background);
				OS.ImageList_Replace (handle, index, hBitmap, hMask);
				OS.DeleteObject (hBitmap);
				OS.DeleteObject (hMask);
				break;
			}
			case DWT.ICON: {
				version(WinCE) {
					OS.ImageList_ReplaceIcon (handle, index, hImage);
				} else {
					HICON hIcon= copyIcon (hImage, cx [0], cy [0]);
					OS.ImageList_ReplaceIcon (handle, index, hIcon);
					OS.DestroyIcon (hIcon);
				}
				break;
			}
			default : break;
		}
	}
	images [index] = image;
}

public void remove (int index) {
	int count = OS.ImageList_GetImageCount (handle);
	if (!(0 <= index && index < count)) return;
	OS.ImageList_Remove (handle, index);
	System.arraycopy (images, index + 1, images, index, --count - index);
	images [index] = null;
}

int removeRef() {
	return --refCount;
}

public int size () {
	int result = 0;
	int count = OS.ImageList_GetImageCount (handle);
	for (int i=0; i<count; i++) {
		if (images [i] !is null) {
			if (images [i].isDisposed ()) images [i] = null;
			if (images [i] !is null) result++;
		}
	}
	return result;
}

}
